package com.bosch.in.rtp1.ept.manager.impl;

import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Workbook;

import com.bosch.in.rtp1.ept.dao.ReleasedHoldDao;
import com.bosch.in.rtp1.ept.manager.ReleasedHoldManager;
import com.bosch.in.rtp1.ept.model.dto.DurationColorCon;
import com.bosch.in.rtp1.ept.model.dto.ReleasedHold;
import com.bosch.in.rtp1.ept.model.technical.Condition4ReleasedHold;
import com.bosch.in.rtp1.ept.util.DaoFactory;
import com.bosch.in.rtp1.ept.util.ExporterUtility;
import com.bosch.in.rtp1.ept.util.ehcache.EhcacheFactory;

public class ReleasedHoldManagerImpl implements ReleasedHoldManager{

	/**
	 * used to manage connection
	 */
	private DBConnectionManager dbManager;
	
	/**
	 * dao object
	 */
	private ReleasedHoldDao releasedHoldDao;
	
	private static final Logger LOGGER = Logger.getLogger(ReleasedHoldManagerImpl.class);
	
	private static final String PDF_PARAM_COND = "con4ReleasedHold";
	    
	private static final String PDF_PARAM_DATE = "reportDate";
	
	public ReleasedHoldManagerImpl() {
	}

	/**
	 * lazy initialize connection when we really need to interact with database and in case 
	 * data can't be found in caching system.
	 * @throws SQLException
	 */
	private void init() throws SQLException {
		dbManager = new DBConnectionManager();
		releasedHoldDao = DaoFactory.getInstance().getReleasedHoldDao(dbManager.getConnection());
	}
	
	@Override
	public List<ReleasedHold> getReleasedHolds(Condition4ReleasedHold condition)
			throws SQLException {
		LOGGER.debug("Begin getReleasedHolds");
		try
		{
			/* get caching data if having */
			List<ReleasedHold> releasedHolds = EhcacheFactory.getReleasedHoldEhcacheWrapper().get(condition.getParameterValues().toString() + condition.getOrderBy());
			if (releasedHolds == null) {
				// lazy init connection
				init();
				releasedHolds = releasedHoldDao.getReleasedHolds(condition);
				
				/* put data to cache */
				EhcacheFactory.getReleasedHoldEhcacheWrapper().put(condition.getParameterValues().toString() + condition.getOrderBy(), releasedHolds);
			}
	    	
			return releasedHolds;
		}
		finally
		{
			if (dbManager != null) {
				dbManager.close();
				LOGGER.debug("Closed connection");
			}
			LOGGER.debug("End getReleasedHolds");
		}
	}

	@Override
	public Workbook exportToExcel(Condition4ReleasedHold searchCriteria, InputStream is, DurationColorCon durCorCon) throws SQLException, IOException
			{
		LOGGER.debug("Begin exportToExcel");
		try {
			// Read data from Ehcache
			List<ReleasedHold> releasedHolds = getReleasedHolds(searchCriteria);
			
			// Exclude record which doesn't match calculated filter heldDuration
			if (!searchCriteria.getHeldDuration().isEmpty() && releasedHolds.size() > 0) { 
				releasedHolds = extractMatchedCalculatedHeldDuration(searchCriteria, releasedHolds);
			}
			
			return ExporterUtility.exportReleasedHoldToExcel(releasedHolds, is, searchCriteria, durCorCon);
		} finally {
			LOGGER.debug("End exportToExcel");
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public JasperPrint exportPdf(Condition4ReleasedHold searchCriteria,
			InputStream reportSource) throws SQLException, JRException {
		
		// Read data from Ehcache
		List<ReleasedHold> releasedHolds = getReleasedHolds(searchCriteria);
		
		// Exclude record which doesn't match calculated filter heldDuration
		if (!searchCriteria.getHeldDuration().isEmpty() && releasedHolds.size() > 0) { 
			releasedHolds = extractMatchedCalculatedHeldDuration(searchCriteria, releasedHolds);
		}
    	
    	// define datasource for pdf content
    	JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(releasedHolds);
    	
    	// populate data in datasource to report
    	Map parameters = new HashMap();
    	
    	parameters.put(PDF_PARAM_COND, searchCriteria);
    	Date today = new Date();
    	parameters.put(PDF_PARAM_DATE, today);
    	
		JasperPrint jasperPrint = JasperFillManager.fillReport(reportSource, parameters, dataSource);
		return jasperPrint;
	}

	@Override
	public boolean updateReleasedHolds(List<ReleasedHold> releaseHolds)
			throws SQLException {
		LOGGER.debug("Begin updateReleasedHolds");
		boolean result = false;
		try
		{
			// lazy init connection
			init();
			result = releasedHoldDao.updateReleasedHolds(releaseHolds);
			
			/* invalidate cache */
			EhcacheFactory.getReleasedHoldEhcacheWrapper().invalidate();
			
			return result;
		}
		finally
		{
			if (dbManager != null) {
				if (result) {
					dbManager.commit();
				}
				dbManager.close();
				LOGGER.debug("Closed connection");
			}
			LOGGER.debug("End updateReleasedHolds");
		}
	}
	
	private List<ReleasedHold> extractMatchedCalculatedHeldDuration(Condition4ReleasedHold searchCriteria,
			List<ReleasedHold> releasedHolds) {
		List<ReleasedHold> result = new ArrayList<ReleasedHold>();
		for (int i = 0; i < releasedHolds.size(); i++) {
			if (String.valueOf(releasedHolds.get(i).getHeldDuration()).indexOf(searchCriteria.getHeldDuration()) >= 0) {
				result.add(releasedHolds.get(i));
			}
		}
		return result;
	}
}
